
#pragma warning(disable:4996)

#include <Windows.h>
#include <process.h>
#include <io.h>
#include <stdio.h>
#include <ctime>
#include <string>
#include <iostream>
#include <fstream>
#include <streambuf>
#include <sstream>
#include <iomanip>

using namespace std;

#include <boost/format.hpp>
#include <boost/lexical_cast.hpp>

#include "Log.h"

namespace yet{

void __ToString(const wstring& ws, string& out, DWORD cp) {
	out = "";
	if (!ws.empty()) {
		DWORD dwMinSize = WideCharToMultiByte(cp, NULL, ws.c_str(), -1, NULL, 0,
				NULL, FALSE);
		if (dwMinSize) {
			out.resize(dwMinSize, 0);
			int n = WideCharToMultiByte(cp, NULL, ws.c_str(), -1, &out[0],
					dwMinSize, NULL, FALSE);
			if (n > 0) {
				out.resize(n - 1);
			} else {
				out = "";
			}
		}
	}
}
void __ToWString(const string& s, wstring& out, DWORD cp) {
	out = L"";
	if (!s.empty()) {
		int dwMinSize = MultiByteToWideChar(cp, 0, s.c_str(), -1, NULL, 0);
		if (dwMinSize > 0) {
			out.resize(dwMinSize, 0);
			int n = MultiByteToWideChar(cp, 0, s.c_str(), -1, &out[0],
					dwMinSize);
			if (n > 0) {
				out.resize(n - 1);
			} else {
				out = L"";
			}
		}
	}
}

bool Logger::toConsole = true;
bool Logger::toDebugWindow = true;
string Logger::filename;

Logger Log;

Logger::Logger(string filename, bool toConsole, bool toDebugWindow) {
	this->filename = filename;
	this->toConsole = toConsole;
	this->toDebugWindow = toDebugWindow;
	isErr = false;
}
void Logger::SetLogFile(string logfile) {
	Logger::filename = logfile;
}
void Logger::SetToConsole(bool toConsole) {
	Logger::toConsole = toConsole;
}
void Logger::SetToDebugWindow(bool toDebugWindow) {
	Logger::toDebugWindow = toDebugWindow;
}
size_t Logger::Length() const {
	return buf.length();
}

void Logger::Append(const string& s, UINT cp) {
	if (cp == GetACP()) {
		buf.append(s);
	} else {
		wstring ws;
		__ToWString(s, ws, cp);
		string ss;
		__ToString(ws, ss, GetACP());
		buf.append(ss);
	}
	if (Length() >= 64) {
		Flush();
	}
}
void Logger::Append(const wstring& ws) {
	string s;
	__ToString(ws, s, GetACP());
	Append(s);
}
void Logger::Flush() {
	if (toDebugWindow) {
		::OutputDebugStringA(buf.c_str());
	}
	if (toConsole) {
		if (isErr) {
			cerr << buf << flush;
		} else {
			cout << buf << flush;
		}
	}
	if (!filename.empty()) {
		FILE* f = 0;
		f = fopen(filename.c_str(), "at");
		if (0 == f) {
			fwrite(buf.c_str(), buf.length(), 1, f);
			fclose(f);
		}
	}
	buf.clear();
}

////Logger& Info(Logger& slog){
////	slog<<"INFO : ";
////	return slog;
////}
////Logger& Error(Logger& slog){
////	slog<<"ERROR: ";
////	return slog;
////}
////Logger& Warn(Logger& slog){
////	slog<<"WARN : ";
////	return slog;
////}
Logger& Timestamp(Logger& slog) {
	SYSTEMTIME t = { 0 };
	GetSystemTime(&t);
	slog.Append(
			boost::str(
					boost::format("[%4d-%02d-%02d %02d:%02d:%02d %03d] ")
							% t.wYear % t.wMonth % t.wDay % t.wHour % t.wMinute
							% t.wSecond % t.wMilliseconds));
	return slog;
}
Logger& ThreadID(Logger& slog) {
	slog.Append(boost::str(boost::format("[%06d] ") % GetCurrentThreadId()));
	return slog;
}

Logger& endl(Logger& slog) {
	slog.Append("\n");
	slog.Flush();
	return slog;
}

Logger& endln(Logger& slog) {
	slog.Append("\n");
	slog.Flush();
	return slog;
}
Logger& flush(Logger& slog) {
	slog.Flush();
	return slog;
}

Logger& info(Logger& slog) {
	slog << Timestamp << ThreadID << "[INFO] ";
	return slog;
}
Logger& err(Logger& slog) {
	slog.isErr = true;
	slog << Timestamp << ThreadID << "[ERROR] ";
	return slog;
}
Logger& error(Logger& slog) {
	slog.isErr = true;
	slog << Timestamp << ThreadID << "[ERROR] ";
	return slog;
}
Logger& warn(Logger& slog) {
	slog << Timestamp << ThreadID << "[WARN] ";
	return slog;
}

Logger& dbg(Logger& slog) {
	slog << Timestamp << ThreadID << "[DEBUG] ";
	return slog;
}
Logger& debug(Logger& slog) {
	slog << Timestamp << ThreadID << "[DEBUG] ";
	return slog;
}

Logger& operator <<(Logger& slog, Logger& (*pFun)(Logger&)) {
	return (*pFun)(slog);
}

Logger& operator <<(Logger& slog, bool val) {
	slog.Append(boost::lexical_cast<string>(val));
	return slog;
}
Logger& operator <<(Logger& slog, char val) {
	slog.Append(boost::lexical_cast<string>(val));
	return slog;
}
Logger& operator <<(Logger& slog, unsigned char val) {
	slog.Append(boost::lexical_cast<string>(val));
	return slog;
}
Logger& operator <<(Logger& slog, short val) {
	slog.Append(boost::lexical_cast<string>(val));
	return slog;
}
Logger& operator <<(Logger& slog, unsigned short val) {
	slog.Append(boost::lexical_cast<string>(val));
	return slog;
}
//vs Ĭ����wchar_tΪ��������!!
Logger& operator <<(Logger& slog, wchar_t val) {
	slog.Append(wstring(&val, 1));
	return slog;
}
Logger& operator <<(Logger& slog, int val) {
	slog.Append(boost::lexical_cast<string>(val));
	return slog;
}
Logger& operator <<(Logger& slog, unsigned int val) {
	slog.Append(boost::lexical_cast<string>(val));
	return slog;
}
Logger& operator <<(Logger& slog, long val) {
	slog.Append(boost::lexical_cast<string>(val));
	return slog;
}
Logger& operator <<(Logger& slog, unsigned long val) {
	slog.Append(boost::lexical_cast<string>(val));
	return slog;
}

Logger& operator <<(Logger& slog, float val) {
	slog.Append(boost::lexical_cast<string>(val));
	return slog;
}
Logger& operator <<(Logger& slog, double val) {
	slog.Append(boost::lexical_cast<string>(val));
	return slog;
}
Logger& operator <<(Logger& slog, long double val) {
	slog.Append(boost::lexical_cast<string>(val));
	return slog;
}

Logger& operator <<(Logger& slog, const char* s) {
	slog.Append(s);
	return slog;
}
Logger& operator <<(Logger& slog, const string& s) {
	slog.Append(s);
	return slog;
}

Logger& operator <<(Logger& slog, const wchar_t* ws) {
	slog.Append(ws);
	return slog;
}
Logger& operator <<(Logger& slog, const wstring& ws) {
	slog.Append(ws);
	return slog;
}

Logger& operator <<(Logger& slog, char* s) {
	slog.Append(s);
	return slog;
}
Logger& operator <<(Logger& slog, string& s) {
	slog.Append(s);
	return slog;
}

Logger& operator <<(Logger& slog, wchar_t* ws) {
	slog.Append(ws);
	return slog;
}
Logger& operator <<(Logger& slog, wstring& ws) {
	slog.Append(ws);
	return slog;
}

}
